﻿using System;
using System.Linq;
using ActiproSoftware.Text;
using ActiproSoftware.Text.Lexing;
using ActiproSoftware.Text.Languages.CSharp.Implementation;
using ActiproSoftware.Text.Languages.DotNet;
using ActiproSoftware.Text.Languages.DotNet.Reflection;
using ActiproSoftware.Text.Parsing;
using ActiproSoftware.Text.Parsing.LLParser;
using ActiproSoftware.Windows.Controls.SyntaxEditor;
using ActiproSoftware.Windows.Controls.SyntaxEditor.EditActions;
using ActiproSoftware.Compatibility;
using ActiproSoftware.Text.Languages.DotNet.Implementation;
using ActiproSoftware.Text.Parsing.Implementation;
using System.Collections.Generic;

namespace CodeEditorTest
{

    /// <summary>
    /// Represents a <c>Simple</c> parser (syntax/semantic analyzer) implementation
    /// that scans code to build a list of all the functions that are defined.
    /// <para>
    /// A real production parser would be better designed to construct an AST of the code,
    /// but this sample is only intended to show an introduction into how a parser can 
    /// be defined and registered with a language.
    /// </para>
    /// </summary>
    public class QueryParser : CSharpParser
    {
        private CSharpSyntaxLanguage language;
        private CSharpProjectAssembly projectAssembly;

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Initializes a new instance of the <c>SimpleParser</c> class.
        /// </summary>
        public QueryParser(CSharpProjectAssembly projectAssembly, CSharpGrammar grammar) : base(grammar) 
        {
            this.language = new CSharpSyntaxLanguage();
            this.projectAssembly = projectAssembly;

            this.language.RegisterProjectAssembly(projectAssembly);
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Performs a parsing operation using the parameters specified in the supplied <see cref="IParseRequest"/>
        /// and returns the resulting parse data.
        /// </summary>
        /// <param name="request">The <see cref="IParseRequest"/> that contains data about the requested parsing operation.</param>
        /// <returns>An <see cref="IParseData"/> that is the result of the parsing operation.</returns>
        /// <remarks>
        /// A <see cref="IParseRequestDispatcher"/> typically calls this method when a queued parse request is ready to be processed.
        /// </remarks>
        public override IParseData Parse(IParseRequest request)
        {
            var parseData = (DotNetParseData) language.Parse(request.Snapshot.Text);

            if (parseData.Errors.Count() > 0)
            {
                var newErrors = new List<IParseError>();

                foreach (IParseError error in parseData.Errors)
                {
                    var startPosition = new TextPosition(error.PositionRange.StartPosition.Line, error.PositionRange.StartPosition.Character);
                    var endPosition = new TextPosition(error.PositionRange.EndPosition.Line, error.PositionRange.EndPosition.Character);

                    var newError = new ParseError(error.Level, error.Description, new TextPositionRange(startPosition, endPosition));

                    newErrors.Add(newError);
                }

                parseData.Errors = newErrors;
            }

            parseData.Snapshot = request.Snapshot;

            return parseData;
        }
    }
}
